package com.alex.demo.controller;

import com.alex.demo.lock.RedisLock;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

@RestController
@Slf4j
public class RedisLockController {
    @Autowired
    RedisTemplate redisTemplate;

    @GetMapping("redisLock")
    public String test01() {
        log.info("我进入了方法");
        String key = "redisKey";
        String value = UUID.randomUUID().toString();
        RedisCallback<Boolean> redisCallback = connection -> {
            // 设置NX
            RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
            // 超时时间
            Expiration expiration = Expiration.seconds(30);
            byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
            byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);
            Boolean result = connection.set(redisKey, redisValue, expiration, setOption);
            return result;
        };

        Boolean lock = (Boolean)redisTemplate.execute(redisCallback);
        if (lock) {
            log.info("我进入了锁");
            try {
                // 业务方法
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                String script = "if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n" +
                        "  return redis.call(\"del\", KEYS[1])\n" +
                        "else\n" +
                        "  return 0\n" +
                        "end";
                List<String> keys = Arrays.asList(key);
                RedisScript<Boolean> redisScript = RedisScript.of(script, Boolean.class);
                // 释放锁的结果
                Boolean result = (Boolean)redisTemplate.execute(redisScript, keys, value);
                log.info("释放锁的结果 --> " + result);
            }
        }
        log.info("方法执行完成");
        return "ok";
    }

    @GetMapping("test02")
    public String test02() {
        RedisLock redisLock = new RedisLock(redisTemplate, "redisKey", 30);
        if (redisLock.lock()){
            log.info("获取redis锁");
            try {
                log.info("执行业务代码");
                Thread.sleep(15000);
                log.info("业务代码执行结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        log.info("释放redis锁");
        redisLock.unLock();
        return "ok";

    }

    public String test03() {
        try (RedisLock redisLock = new RedisLock(redisTemplate, "redisKey", 30)) {
            // 如果成功获取锁
            if (redisLock.lock()) {
                // 执行业务代码
                Thread.sleep(15000);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return "ok";
    }


}
